#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/time.h>
#include <math.h>
#include <time.h>
//#include "vector"
#include "rngs.h"

#define DEBUG 0
#define NUM_TESTS 1000
#define NOISY_TEST 0
const int cards5coins[24] = {	curse, 		estate, 	duchy, 		copper, 	silver, council_room, 	feast, 	gardens, 
							mine, 		remodel, 	smithy, 	village, 	baron, 	great_hall, 	minion, steward, 
							tribute, 	ambassador, cutpurse, 	embargo, 	outpost, salvager, 		sea_hag, treasure_map};

float rndm() {//provides a pseudo-rndm number.
	struct timeval tv;
	float retVal;
	
	gettimeofday(&tv, NULL);  //the only way this 
	retVal = tv.tv_usec * tv.tv_sec;
	
	while (retVal > 1.0) {
		retVal = retVal / 10;
	}
	retVal = retVal * (float)rand()/RAND_MAX;
	if(retVal < 0) {retVal = retVal * (-1);}
	return retVal;
}

int testFeast(int testIteration, struct gameState *state, int kingCards[10]) {
	int randCardCostOk = 0;
	int i, j;
	int cardToBuy = -1, success = 1;
	int currentTurn = 0, feastPresent = -1;
	int cardEffectRet;
	
	if (state->handCount[currentTurn] > 0) { //check if hand is empty
		for (i=0;i<state->handCount[currentTurn];i++) {	//check if feast is present
			if (state->hand[currentTurn][i] == feast) {feastPresent = i;}
		}
	} else {
		for (i=0;i<5;i++) { //fill hand if empty
			state->hand[currentTurn][i] = (int) roundf( treasure_map * rndm() );
			state->handCount[currentTurn] = i + 1;
		}
	}
	//assign feast to a rndm spot in the hand if it's not already present
	if (feastPresent == -1){
		feastPresent = (int) roundf( (state->handCount[currentTurn]-1) * rndm() );
		state->hand[currentTurn][feastPresent] = feast;
	}
	if (NOISY_TEST == 1) {
		printf("\tfeast in hand at position: %d\n\tHand is:  ", feastPresent);
		for (j=0;j<10;j++)
			printf("%d, ", state->hand[currentTurn][j]);
		printf("\n");
	}
	//while (randCardCostOk == 0) { 
	//was used to ensure all cards' tested cost was ok, but this shouldn't always be the case
		cardToBuy = kingCards[ (int) roundf(9 * rndm() ) ]; //assign the card to be gained as a rndm one of the kingdom cards
		for (i=0;i<24;i++) {
			if (cardToBuy == cards5coins[i]) { randCardCostOk = 1;}
		}
	//}
	if (NOISY_TEST == 1)
		printf("\tcardToBuy is: %d, is cost ok? %d\n", cardToBuy, randCardCostOk);
	int numDiscard = state->discardCount[currentTurn];
	if (NOISY_TEST == 1)
		printf("\tNumber of cards in discard: %d\n", numDiscard);
	
	if( (getCost(cardToBuy) > 5) && (supplyCount(cardToBuy, state) < 1) ){
		if (NOISY_TEST == 1)
			printf("\tCard is %d and is too expensive and supply is too low, cardEffect() should return -1:  \n", cardToBuy);
		if (-1 == cardEffect(feast, cardToBuy,0,0,state,feastPresent,0)) {
			if (state->hand[currentTurn][feastPresent] == feast) {
				success = 1;
				if (NOISY_TEST == 1)
					printf("\tTEST %d PASSED:  cardEffect() did notice that the card was too expensive and in too low of supply\n", testIteration);
			} else {
				success = 0;
				if (NOISY_TEST > 0){
					if (NOISY_TEST == 1) {
						printf("\tPost-play hand is:  ");
						for (j=0;j<10;j++)
							printf("%d, ", state->hand[currentTurn][j]);
						printf("\n");
					}
					printf("\tTEST %d FAILED:  cardEffect() new that the card was too expensive and in too low of supply, but feast left the hand anyways\n", testIteration);
				}
			}
			if (NOISY_TEST > 0)
				printf("\tTEST %d FAILED:  cardEffect() Did not notice that the card was too expensive and in too low supply\n", testIteration);
		} else {
			success = 0;
			if (NOISY_TEST > 0){
				if (NOISY_TEST == 1) {
					printf("\tPost-play hand is:  ");
					for (j=0;j<10;j++)
						printf("%d, ", state->hand[currentTurn][j]);
					printf("\n");
				}
				printf("\tTEST %d FAILED:  cardEffect() Did not notice that the card was too expensive and in too low supply\n", testIteration);
			}
		}
	} else if (getCost(cardToBuy) > 5) {
		if (NOISY_TEST == 1)
			printf("\tCard is %d and is too expensive, cardEffect() should return -1:  \n", cardToBuy);
		if (-1 == cardEffect(feast, cardToBuy,0,0,state,feastPresent,0)) {
			if (state->hand[currentTurn][feastPresent] == feast) {
				success = 1;
				if (NOISY_TEST == 1)
					printf("\tTEST %d PASSED:  cardEffect() did notice that the card was too expensive\n", testIteration);
			} else {
				success = 0;
				if (NOISY_TEST > 0){
					if (NOISY_TEST == 1) {
						printf("\tPost-play hand is:  ");
						for (j=0;j<10;j++)
							printf("%d, ", state->hand[currentTurn][j]);
						printf("\n");
					}
					printf("\tTEST %d FAILED:  cardEffect() new that the card was too expensive, but feast left the hand anyways\n", testIteration);
				}
			}
		} else {
			success = 0;
			if (NOISY_TEST > 0){
				if (NOISY_TEST == 1) {
					printf("\tPost-play hand is:  ");
					for (j=0;j<10;j++)
						printf("%d, ", state->hand[currentTurn][j]);
					printf("\n");
				}
				printf("\tTEST %d FAILED:  cardEffect() Did not notice that the card was too expensive\n", testIteration);
			}
		}
	} else if (supplyCount(cardToBuy, state) < 1 ) {
		if (NOISY_TEST == 1)
			printf("\tCard is %d and supply is too low, cardEffect() should return -1:  \n", cardToBuy);
		if (-1 == cardEffect(feast, cardToBuy,0,0,state,feastPresent,0)) {
			if (state->hand[currentTurn][feastPresent] == feast) {
				success = 1;
				if (NOISY_TEST == 1)
					printf("\tTEST %d PASSED:  cardEffect() did notice that the card was in too low supply\n", testIteration);
				} else {
				success = 0;
				if (NOISY_TEST > 0){
					if (NOISY_TEST == 1) {
						printf("\tPost-play hand is:  ");
						for (j=0;j<10;j++)
							printf("%d, ", state->hand[currentTurn][j]);
						printf("\n");
					}
					printf("\tTEST %d FAILED:  cardEffect() knew that the card was in too low supply, but feast left the hand anyways\n", testIteration);
				}
			}
		} else {
			success = 0;
			if (NOISY_TEST > 0){
				if (NOISY_TEST == 1) {
					printf("\tPost-play hand is:  ");
					for (j=0;j<10;j++)
						printf("%d, ", state->hand[currentTurn][j]);
					printf("\n");
				}
				printf("\tTEST %d FAILED:  cardEffect() Did not notice that the card was in too low supply\n", testIteration);
			}
		}
	} else {
		cardEffectRet = cardEffect(feast, cardToBuy,0,0,state,feastPresent,0);
		if (NOISY_TEST == 1)
			printf("\tcardEffect() returned:  %d\n", cardEffectRet);
		if (0 == cardEffectRet ) {
			//card supposedly played correctly
			if (state->discard[currentTurn][numDiscard] != cardToBuy || 
						state->discardCount[currentTurn]  != numDiscard + 1) {
						//card was gained either because number of discard cards is greater or 
							//the card requested is on the top of the stack
				if (NOISY_TEST > 0)
					printf("\tTEST %d FAILED:  %d should be at last position of discard, but isn't\n", testIteration, cardToBuy);
				success = 0;
			}
			if ( state->hand[currentTurn][feastPresent] == feast) { 
				//the last instance of feast in the hand was set to feastPresent, so this cannot be true
				if (NOISY_TEST == 1){
					if (NOISY_TEST == 1) {
						printf("\tPost-play hand is:  ");
						for (j=0;j<10;j++)
							printf("%d, ", state->hand[currentTurn][j]);
						printf("\n");
					}
					printf("\tTEST %d FAILED:  feast should not be at %d of hand, but is\n", testIteration, feastPresent);
				}
				success = 0;
			} else {
				if (NOISY_TEST == 1) {
					printf("\tPost-play hand is:  ");
					for (j=0;j<10;j++)
						printf("%d, ", state->hand[currentTurn][j]);
					printf("\n");
				}
				success = 1;
			}
		} else {
			//card play failed
			if (NOISY_TEST > 0){
				if (NOISY_TEST == 1) {
					printf("\tPost-play hand is:  ");
					for (j=0;j<10;j++)
						printf("%d, ", state->hand[currentTurn][j]);
					printf("\n");
				}
				printf("\tTEST %d FAILED:  %d cardEffect returned '%d', should be '0'\n", testIteration, cardToBuy, cardEffectRet);
				success = 0;
			}
		}
	}
	
	if (success == 1) {
		if (NOISY_TEST == 1)
			printf("\tTEST %d SUCCEEDED\n", testIteration);
		return 0;
	} else {
		return -1;
		
	}
}

int main(int argc, char **argv) {
	int i, j, k;
	int feastPresent = -1; //used to ensure that feast gets in the game
	int numPlayers, seed, card[10];
	struct gameState G;
	int numPassed = 0, numFailed = 0;
	
	printf("STARTING RANDOM TEST FOR FEAST\n");
	for (i=0;i<NUM_TESTS;i++) {
		numPlayers = (int) roundf( ((MAX_PLAYERS-1) * rndm())+1 );
		seed = (int) roundf( 32767 * rndm() );  //generate a rndm seed
		if (NOISY_TEST == 1)
			printf("Starting Test %d\n\tPlayers: %d, Seed: %d\n\tCards: ", i, numPlayers, seed);
		for (j=0;j<10;j++) { // assign the ten cards for the game
			card[j] = (int) roundf( treasure_map * rndm() ); //use highest-numbered card as max of rndm()
			for (k=0;k<j;k++) { 
				if (card[k] == card[j]) { 
					j = j - 1;
				} 
			} // ensure no cards are assigned in duplicate
			if (card[j] == feast) {feastPresent = 1;} //verify if this is feast
		}
		if (feastPresent == -1) { card[ (int) roundf( 10*rndm() ) ] = feast;}
		for (j=0;j<10;j++)
			if (NOISY_TEST == 1)
				printf("%d, ", card[j]);
		if (NOISY_TEST == 1)
			printf("\n");
		//put feast in a rndm  position, only if it's not already in the game
		
		initializeGame(numPlayers, card, seed, &G);
		if (testFeast(i, &G, card) == 0)
			numPassed += 1;
		else
			numFailed += 1;
	}
	printf("%d%% success, %d tests passed and %d failed\n", 100*numPassed/NUM_TESTS, numPassed, numFailed);
	return 0;
}